package ferp.core.ai.tree2;

/**
 * User: olegs
 * Date: 1/10/13 9:21 PM
 */
public class LinkedList<T extends LinkedList.Entry<T>>
{
  // Linked list entry base class
  public static class Entry<T extends Entry>
  {
    public T previous;
    public T next;
  }

  public LinkedList(Class<T> clazz)
  {
    try
    {
      head = clazz.newInstance();
      tail = clazz.newInstance();

      clear();
    }
    catch (Exception e)
    {
      throw new RuntimeException(e);
    }
  }

  public final void clear()
  {
    head.next = tail;
    tail.previous = head;

    iterator = tail;

    size = 0;
  }

  public final void addFirst(T e)
  {
    e.next = head.next;
    head.next.previous = e;
    head.next = e;
    e.previous = head;

    size++;
  }

  public final void addLast(T e)
  {
    e.previous = tail.previous;
    tail.previous.next = e;
    tail.previous = e;
    e.next = tail;

    size++;
  }

  public final T removeFirst()
  {
    T e = head.next;

    head.next = e.next;
    e.next.previous = head;

    size--;

    return e;
  }

  public final T removeLast()
  {
    T e = tail.previous;

    tail.previous = e.previous;
    e.previous.next = tail;

    size--;

    return e;
  }

  public final void remove(T e)
  {
    e.previous.next = e.next;
    e.next.previous = e.previous;

    size--;
  }

  public final T first()
  {
    return head.next;
  }

  // reset internal iterator
  public final void start()
  {
    iterator = head.next;
  }

  // check if iterator can advance
  public final boolean hasNextEntry()
  {
    return iterator != tail;
  }

  // return the next element in iteration cycle and advance internal iterator
  public final T nextEntry()
  {
    T next = iterator;

    iterator = iterator.next;

    return next;
  }

  // remove current element
  public final void removeCurrentEntry()
  {
    T current = iterator.previous;

    current.previous.next = current.next;
    current.next.previous = current.previous;

    size--;
  }

  public final int size() {return size;}

  public final T get(int index)
  {
    T e;
    int i = 0;

    start();

    do
    {
      e = nextEntry();
    } while (i++ < index);

    return e;
  }

  // list head
  private T head;
  // list tail
  private T tail;
  // list size
  private int size;
  // internal list iterator pointed to element followed by the current one
  private T iterator;

/*
  public static void main(String[] argv)
  {
    Entry e1 = new Entry();
    System.out.println("e1 = " + e1);

    Entry e2 = new Entry();
    System.out.println("e2 = " + e2);

    Entry e3 = new Entry();
    System.out.println("e3 = " + e3);

    LinkedList<Entry> list = new LinkedList<Entry>();

    list.addLast(e1);
    list.addLast(e2);
    list.addLast(e3);

    for (list.start(); list.hasNextEntry();)
      System.out.println(list.nextEntry());

    for (int i = 0; i < list.size; ++i)
      System.out.println(list.get(i));


    for (list.start(); list.hasNextEntry();)
    {
      Entry e = list.nextEntry();

      list.removeCurrentEntry();

      System.out.println(e + " removed");
    }

    for (list.start(); list.hasNextEntry();)
      System.out.println(list.nextEntry());

    list.addFirst(e1);
    for (list.start(); list.hasNextEntry();)
    {
      Entry e = list.nextEntry();

      list.removeCurrentEntry();

      System.out.println(e + " removed");
    }

    System.out.println(list.hasNextEntry());

    list.addLast(e1);
    list.addLast(e2);
    list.addLast(e3);

    for (int i = 0; i < list.size(); ++i)
      System.out.println("e" + i + " = " + list.get(i));
  }
*/
}
